package com.gitee.urick.union.api.union.handler.v2;


import cn.hutool.core.util.ObjectUtil;
import com.gitee.urick.union.api.union.IHandler;
import com.gitee.urick.union.api.union.dto.ReqCtx;
import com.gitee.urick.union.api.union.dto.base.BaseReq;
import com.gitee.urick.union.api.union.dto.base.BaseRes;
import com.gitee.urick.union.utils.TipsCode;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.stereotype.Component;

import javax.annotation.PostConstruct;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;

/**
 * 修改记录
 * +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 * 修改日期				修改者						备注信息
 * +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 * 2020年08月25日			kkroc							初始化版本
 */
@Slf4j
@Component("dispatcher_v2")
public class DispatcherV2 implements IHandler {
    @Autowired
    private Set<Api> apiSet;

    private Map<String, CacheMethod> cacheMethod;

    /**
     * 初始化API基建
     */
    @PostConstruct
    public void init() {
        cacheMethod = new HashMap<>();
        apiSet.forEach(m -> {
            Class<? extends Api> aClass = m.getClass();
            Component annotation = aClass.getAnnotation(Component.class);
            if (ObjectUtil.isNotNull(annotation)) {
                String value = annotation.value();
                Method[] methods = aClass.getMethods();
                for (Method method : methods) {
                    if (!Modifier.isPublic(method.getModifiers())) {
                        continue;
                    }
                    Class<?>[] parameterTypes = method.getParameterTypes();
                    if (ObjectUtil.isNull(parameterTypes) || parameterTypes.length != 1 || !BaseReq.class.isAssignableFrom(parameterTypes[0])) {
                        continue;
                    }
                    cacheMethod.put(value + "_" + method.getName(), CacheMethod.build(m, method, parameterTypes[0]));
                }
            }
        });
    }

    @Override
    public void beforeHandle(ReqCtx ctx) {
    }


    @Override
    public void handle(ReqCtx ctx) {
        if (!cacheMethod.containsKey(ctx.getAction())) {
            ctx.setRes(new BaseRes().error("不支持的请求类型：" + ctx.getAction()));
        } else {
            CacheMethod method = cacheMethod.get(ctx.getAction());
            try {
                BaseRes result = (BaseRes) method.getMethod().invoke(method.getInstance(), ctx.getReq(method.getParams()));
                ctx.setRes(result);
            } catch (Exception e) {
                log.error("调用服务方法：{}，异常", ctx.getAction(), e);
                ctx.makeTips(TipsCode.System_Error);
            }
        }
    }

    @Override
    public void afterHandle(ReqCtx ctx) throws Exception {

    }

    private static class CacheMethod {
        private Object instance;
        private Method method;
        private Class<?> params;

        private CacheMethod(Object instance, Method method, Class<?> params) {
            this.instance = instance;
            this.method = method;
            this.params = params;
        }

        public Object getInstance() {
            return instance;
        }

        public void setInstance(Object instance) {
            this.instance = instance;
        }

        public Method getMethod() {
            return method;
        }

        public void setMethod(Method method) {
            this.method = method;
        }

        public Class<?> getParams() {
            return params;
        }

        public void setParams(Class<?> params) {
            this.params = params;
        }

        static CacheMethod build(Object instance, Method method, Class<?> paramsType) {
            return new CacheMethod(instance, method, paramsType);
        }
    }
}
